import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

/**
 * An implementation of the lister.
 * 
 * The listing adds to each line its location and its binary translation, for
 * those lines which define instructions. It is the most complete output
 * produced by the parser.
 * 
 * @author Andrew Krieger
 * @version 0.1
 * @since 6 Apr 2012
 */

public class Listing implements IListing {

	private final List<Instruction> lister = new ArrayList<Instruction>();

	/**
	 * Add a parsed line to the listing.
	 * 
	 * A line may be an instruction, a directive, or a pure comment. The first
	 * two are handled the same from the outside; just pass in the right
	 * mnemonic and the IListing object will decide which it is. A pure comment
	 * should have its mnemonic set to null.
	 * 
	 * @param line
	 *            The line number being parsed
	 * @param label
	 *            The label on the line, or null if there is none
	 * @param comment
	 *            The comment on the line, or nul if there is none
	 * @param mnemonic
	 *            The mnemonic, or null for a pure comment
	 * @param ops
	 *            A list of operands, possibly empty
	 */
	@Override
	public void addLine(int line, String label, String comment,
			Mnemonic mnemonic, Iterable<Operand> ops) {
		int instLine = line;
		if (Mnemonic.isInstruction(mnemonic)) {
			line++;
		} else {
			if (menomic.toString() == "NEWLC") {
				line = ops[0];
				// TODO: make sure no array out of bound exception
			} else if (mnemonic.toString() == "SKIPS") {
				line += ops[0];
				// depends how ops are formatted
			} else if (mnemonic.toString() == "KICKO") {
				line = ops[0];
				// depends how ops are formatted
			}
		}
		if (line > 4095) {
			// TODO: out of memory error
		}

		Instruction inst = new Instruction(instLine, label, comment, mnemonic,
				ops);
		this.lister.add(inst);
	}

	@Override
	public int getCurrentLC() {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * Print a listing file to the supplied Stream
	 * 
	 * Formats and outputs a listing file, according to the specifed format.
	 * 
	 * @param os
	 *            The stream to write to
	 * @throws IOException
	 *             If an I/O error occurs
	 */
	@Override
	public void print(OutputStream os) throws IOException {
		// [PrintStream used for outputting the SymbolTable]
		PrintStream out = new PrintStream(os);

		out.println("LC\tOpcode\tLabel\tOperands");

		for (Instruction inst : this.lister) {
			out.print(inst.line + "\t"
					+ Integer.toBinaryString(inst.getBinary()) + "\t"
					+ inst.label + "\t");
			for (Operand op : inst.ops) {
				out.print(op);
			}
			out.println();
		}
	}
}
